#ifndef _OBJECT_POOL_HPP_20120407
#define _OBJECT_POOL_HPP_20120407

#include "base.hpp"
#include "fixed_size_allocator.hpp"

template <typename _T>
class ObjectPool
{
	public :
		ObjectPool(int obj_num);
		~ObjectPool();

		void destroy(_T * pObj);

		_T * construct();

		template <typename _P1>
			_T * construct(_P1 & p1);

		template <typename _P1, typename _P2>
			_T * construct(_P1 & p1, _P2 & p2);

		template <typename _P1, typename _P2, typename _P3>
			_T * construct(_P1 & p1, _P2 & p2, _P3 & p3);

		template <typename _P1, typename _P2, typename _P3, typename _P4>
			_T * construct(_P1 & p1, _P2 & p2, _P3 & p3, _P4 & p4);
		
		bool empty() { return _alloc.empty(); }
		int  free_count() { return _alloc.free_count(); }
	
	public :
		FixedSizeAllocator _alloc;
};

template <typename _T>
ObjectPool<_T>::ObjectPool(int obj_num)
	: _alloc(sizeof(_T), obj_num)
{
}

template <typename _T>
ObjectPool<_T>::~ObjectPool()
{
}

template <typename _T>
void ObjectPool<_T>::destroy(_T * pObj)
{
	pObj->~_T();
	_alloc.deallocate((void*)pObj);
}

template <typename _T>
_T * ObjectPool<_T>::construct()
{
	void * addr = _alloc.allocate();

	if (NULL != addr)
	{
		new (addr) _T;
	}

	return (_T*)addr;
}

template <typename _T>
template <typename _P1>
_T * ObjectPool<_T>::construct(_P1 & p1)
{
	void * addr = _alloc.allocate();

	if (NULL != addr)
	{
		new (addr) _T(p1);
	}

	return (_T*)addr;
}

template <typename _T>
template <typename _P1, typename _P2>
_T * ObjectPool<_T>::construct(_P1 & p1, _P2 & p2)
{
	void * addr = _alloc.allocate();

	if (NULL != addr)
	{
		new (addr) _T(p1, p2);
	}

	return (_T*)addr;
}

template <typename _T>
template <typename _P1, typename _P2, typename _P3>
_T * ObjectPool<_T>::construct(_P1 & p1, _P2 & p2, _P3 & p3)
{
	void * addr = _alloc.allocate();

	if (NULL != addr)
	{
		new (addr) _T(p1, p2, p3);
	}

	return (_T*)addr;
}

template <typename _T>
template <typename _P1, typename _P2, typename _P3, typename _P4>
_T * ObjectPool<_T>::construct(_P1 & p1, _P2 & p2, _P3 & p3, _P4 & p4)
{
	void * addr = _alloc.allocate();

	if (NULL != addr)
	{
		new (addr) _T(p1, p2, p3, p4);
	}

	return (_T*)addr;
}

#endif

